/*
 * Roberts.cpp
 *
 *  Created on: Dec 7, 2009
 */

#include "Roberts.h"
#include <math.h>
#include <mpi.h>

Roberts::Roberts(int limiar) {
	setLimiar(limiar);
}

Roberts::~Roberts() {
}

void Roberts::applyFilterInVector(int width, int height, int **vectors, int **newVectors) {
	int rank;
	MPI_Comm_rank ( MPI_COMM_WORLD, & rank);

	int proccess;
	MPI_Comm_size( MPI_COMM_WORLD, & proccess);

	int qtd = 0;
	int rest = 0;
	int max = qtd;

	qtd = height / proccess;
	rest = height % proccess;
	max = qtd * (rank + 1);

	if (rank == 0) {
		qtd += rest;
		max += rest;
	}


	int sendVector[qtd][width];
	int iRank = 0;

	for (int i = rank * qtd; i < max; i++) {
		#pragma omp parallel for default(shared)
		for (int j = 0; j < width; j++) {
			int centerRight = getCenterRightValue(i, j, width, height, vectors);
			int dowRight = getDownRightValue(i, j, width, height, vectors);
			int dowCenter = getDownCenterValue(i, j, width, height, vectors);

			int tmp = sqrt((pow((dowRight - vectors[i][j]),2) + pow((dowCenter - centerRight),2)));

			if (getLimiar() > 255) {
				if (rank == 0) {
					newVectors[i][j] = tmp;
				} else {
					sendVector[iRank][j] = tmp;

				}
			} else {
				if (rank == 0) {
					newVectors[i][j] = (tmp > limiar) ? 255 : 0;
				} else {
					sendVector[iRank][j] = (tmp > limiar) ? 255 : 0;

				}
			}
		}

		iRank++;
	}

	if (rank != 0) {
		MPI_Send(sendVector, qtd*width, MPI_INT, 0, 1, MPI_COMM_WORLD);
	}

	if (rank == 0) {
		for (int i = 1; i < proccess; i ++) {
			int recvVector[qtd][width];
			MPI_Status status;

			MPI_Recv(recvVector, qtd*width, MPI_INT, i, 1, MPI_COMM_WORLD, &status);

			int index = i * qtd;

			for (int line = 0; line < qtd; line++) {
				for (int column = 0; column < width; column++) {
					newVectors[index][column] = recvVector[line][column];
				}

				index++;
			}

			int ok = 1;
			MPI_Send(&ok, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
		}
	} else {
		int isOk;
		MPI_Status status;
		MPI_Recv(&isOk, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
	}
}

void Roberts::setLimiar(int limiar) {
	this->limiar = limiar;
}

int Roberts::getLimiar() {
	return limiar;
}
